package com.fudan.adse.service.impl;

import com.fudan.adse.domain.bo.SeatBO;
import com.fudan.adse.domain.cont.CheckStatus;
import com.fudan.adse.domain.cont.OrderStatus;
import com.fudan.adse.domain.cont.SeatStatus;
import com.fudan.adse.domain.po.TicketOrder;
import com.fudan.adse.domain.po.TicketOrderExample;
import com.fudan.adse.grpc.OrderGrpc;
import com.fudan.adse.grpc.OrderQuery;
import com.fudan.adse.grpc.OrderResponse;
import com.fudan.adse.mbg.mapper.TicketOrderMapper;
import com.fudan.adse.utils.StringUtil;
import com.google.protobuf.Empty;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @author Jerry Zhang
 * create: 2022-11-24 15:53
 */
@Slf4j
@GrpcService
public class OrderGrpcServiceImpl extends OrderGrpc.OrderImplBase {
    @Autowired
    private TicketOrderMapper orderMapper;

    /**
     * 获取某场次座位 最新 使用情况
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void listSeatsByRowPieceId(OrderQuery request, StreamObserver<OrderResponse> responseObserver) {
        TicketOrderExample example = new TicketOrderExample();
        example.createCriteria().andRowPieceIdIn(request.getRowPieceIdList());
        Map<Integer, List<TicketOrder>> rowPieceOrdersMap = orderMapper.selectByExample(example).stream()
                .collect(Collectors.groupingBy(TicketOrder::getRowPieceId));
        List<OrderResponse.SeatVO> retList = new ArrayList<>();
        rowPieceOrdersMap.forEach((rowPieceId, orders) -> {
            // 根据订单更新时间排序
            orders.sort(Comparator.comparing(TicketOrder::getUpdateTime));
            Set<Integer> busySeats = new HashSet<>(8);
            Set<Integer> freeSeats = new HashSet<>(8);
            for (int i = orders.size() - 1; i >= 0; i--) {
                int[] seats = StringUtil.spiltToIntArr(orders.get(i).getSeats());
                if (!OrderStatus.CANCEL.getStatus().equals(orders.get(i).getStatus())) {
                    if (!CheckStatus.REFUND.getStatus().equals(orders.get(i).getCheckStatus())) {
                        addAllToSet(seats, busySeats, freeSeats);
                    } else {
                        addAllToSet(seats, freeSeats, busySeats);
                    }
                } else {
                    addAllToSet(seats, freeSeats, busySeats);
                }
            }
            busySeats.forEach(i->{
                SeatBO seat = new SeatBO();
                seat.init(i, rowPieceId, SeatStatus.BUSY);
                retList.add(OrderResponse.SeatVO.newBuilder()
                        .setRowPieceId(rowPieceId)
                        .setId(seat.getId())
                        .setRow(seat.getRow())
                        .setCol(seat.getCol())
                        .setStatus(seat.getStatus().name())
                        .build());
            });
            freeSeats.forEach(i->{
                SeatBO seat = new SeatBO();
                seat.init(i, rowPieceId, SeatStatus.FREE);
                retList.add(OrderResponse.SeatVO.newBuilder()
                        .setRowPieceId(rowPieceId)
                        .setId(seat.getId())
                        .setRow(seat.getRow())
                        .setCol(seat.getCol())
                        .setStatus(seat.getStatus().name())
                        .build());
            });
        });
        responseObserver.onNext(OrderResponse.newBuilder().addAllSeat(retList).build());
        responseObserver.onCompleted();
    }

    private void addAllToSet(int[] seats, Set<Integer> addToSet, Set<Integer> notInSet) {
        for (int seat : seats) {
            if (!notInSet.contains(seat)) {
                addToSet.add(seat);
            }
        }
    }

    /**
     * 影片开始放映后，将相关影票设置为已使用
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void checkAllTickets(OrderQuery request, StreamObserver<Empty> responseObserver) {
        //todo 影片开始放映后，根据排片场次 id，将相关影票设置为已使用
    }
}
